package main

import (
	"errors"
	"fmt"
)

func positive(val int) (err error) {
	if val < 0 {
		err = errors.New("should be non-negative numbers")
		return
	}
	return
}

func twice(array []int) {
	for key := range array {
		array[key] *= 2
	}
}

func counter_generator() func() int {
	var i = 0
	return func() int {
		i++
		return i
	}
}

func add(args ...int) (ret int) {
	for _, val := range args {
		ret += val
	}
	return
}

func panic_call() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("recover:%v\n", r)
		}
	}()
	panic("runtime error")
}

func print(args ...interface{}) {
	for _, arg := range args {
		switch arg.(type) {
		case int:
			fmt.Println(arg, "is a int value")
		case string:
			fmt.Println(arg, "is a string value")
		case float32:
			fmt.Println(arg, "is a float32 value")
		case float64:
			fmt.Println(arg, "is a float64 value")
		case interface{}:
			fmt.Println(arg, "is a interface")
		default:
			fmt.Println(arg, "is a unknow type")
		}
	}
}

type Printer struct {
	val interface{}
}

func (this *Printer) print(args ...interface{}) {
	switch this.val.(type) {
	case int:
		fmt.Println(this.val, "is a int value")
	case string:
		fmt.Println(this.val, "is a string value")
	case float32:
		fmt.Println(this.val, "is a float32 value")
	case float64:
		fmt.Println(this.val, "is a float64 value")
	case interface{}:
		fmt.Println(this.val, "is a interface")
	default:
		fmt.Println(this.val, "is a unknow type")
	}
	args = append(args, this.val)
	print(args)
}

func main() {
	array := []int{1, 2, 3, 4, 5}
	fmt.Println(add(1, 2, 3, 4, 5))
	fmt.Println(add(array...))

	counter1 := counter_generator()
	counter2 := counter_generator()
	counter1()
	counter1()
	counter1()
	fmt.Println(counter1())
	fmt.Println(counter2())

	twice(array)
	fmt.Println(array)

	if positive(10) == nil {
		fmt.Println("positive")
	}

	if positive(-1) != nil {
		fmt.Println("negative")
	}

	print(1, "val", 3.0)
	printer := &Printer{"val"}
	var call func(...interface{})
	call = printer.print
	call()

	panic_call()

	func() { fmt.Println("anonymous func") }()

}
